package br.com.colegio.dao.storage;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import br.com.colegio.dao.BoletoDAO;
import br.com.colegio.util.UtilData;
import br.com.colegio.vo.Boleto;

public class BoletoData {
	private static BoletoData instance;
	private Map<String,Boleto> data = new TreeMap<String, Boleto>();
	private Map<String,Set<Boleto>> dataAluno = new TreeMap<String,Set<Boleto>>();
	private Map<String,Map<String,Map<String,Boleto>>> dataFiltro = new TreeMap<String,Map<String,Map<String,Boleto>>>();

	private BoletoData(){}

	public static BoletoData getInstance(){
		if(instance == null)
			instance = new BoletoData();

		return instance;
	}

	private Map<String,Boleto> getData(){
		if(data.size() == 0){
			Collection<Object> r = BoletoDAO.list();

			if(r != null)
				for(Object o : r){
					Boleto b = (Boleto)o;
					data.put(b.getCodigo(),b);

					if(!dataAluno.containsKey(b.getAlunoBoleto().getCodigo()))
						dataAluno.put(b.getAlunoBoleto().getCodigo(),new HashSet<Boleto>());

					dataAluno.get(b.getAlunoBoleto().getCodigo()).add(b);

					if(dataFiltro.containsKey(b.getStatusBoleto().getCodigo())){
						if(dataFiltro.get(b.getStatusBoleto().getCodigo()).containsKey(UtilData.format(b.getDataVencimento(),"yyyyMM")))
							dataFiltro.get(b.getStatusBoleto().getCodigo()).get(
									UtilData.format(b.getDataVencimento(),"yyyyMM")).put(b.getCodigo(),b);
						else {
							dataFiltro.get(b.getStatusBoleto().getCodigo()).put(
									UtilData.format(b.getDataVencimento(),"yyyyMM"),new HashMap<String,Boleto>());
							dataFiltro.get(b.getStatusBoleto().getCodigo()).get(
									UtilData.format(b.getDataVencimento(),"yyyyMM")).put(b.getCodigo(),b);
						}
					}
					else {
						dataFiltro.put(b.getStatusBoleto().getCodigo(),new HashMap<String,Map<String,Boleto>>());
						dataFiltro.get(b.getStatusBoleto().getCodigo()).put(
								UtilData.format(b.getDataVencimento(),"yyyyMM"),new HashMap<String,Boleto>());
						dataFiltro.get(b.getStatusBoleto().getCodigo()).get(
								UtilData.format(b.getDataVencimento(),"yyyyMM")).put(b.getCodigo(),b);
					}
				}
		}
		return data;
	}

	public Boleto get(String cod){
		return getData().get(cod);
	}

	public void atualizaData(Boleto b){
		getData().put(b.getCodigo(),b);

		if(dataFiltro.containsKey("A"))
			if (dataFiltro.get("A").containsKey(UtilData.format(b.getDataVencimento(),"yyyyMM")))
				dataFiltro.get("A").get(UtilData.format(b.getDataVencimento(),"yyyyMM")).remove(b.getCodigo());

		if(dataFiltro.containsKey("C"))
			if (dataFiltro.get("C").containsKey(UtilData.format(b.getDataVencimento(),"yyyyMM")))
				dataFiltro.get("C").get(UtilData.format(b.getDataVencimento(),"yyyyMM")).remove(b.getCodigo());

		if(dataFiltro.containsKey("P"))
			if (dataFiltro.get("P").containsKey(UtilData.format(b.getDataVencimento(),"yyyyMM")))
				dataFiltro.get("P").get(UtilData.format(b.getDataVencimento(),"yyyyMM")).remove(b.getCodigo());

		if(!dataAluno.containsKey(b.getAlunoBoleto().getCodigo()))
			dataAluno.put(b.getAlunoBoleto().getCodigo(),new HashSet<Boleto>());

		dataAluno.get(b.getAlunoBoleto().getCodigo()).add(b);

		if(dataFiltro.containsKey(b.getStatusBoleto().getCodigo())){
			if(dataFiltro.get(b.getStatusBoleto().getCodigo()).containsKey(UtilData.format(b.getDataVencimento(),"yyyyMM")))
				dataFiltro.get(b.getStatusBoleto().getCodigo()).get(
						UtilData.format(b.getDataVencimento(),"yyyyMM")).put(b.getCodigo(),b);
			else {
				dataFiltro.get(b.getStatusBoleto().getCodigo()).put(
						UtilData.format(b.getDataVencimento(),"yyyyMM"),new HashMap<String,Boleto>());
				dataFiltro.get(b.getStatusBoleto().getCodigo()).get(
						UtilData.format(b.getDataVencimento(),"yyyyMM")).put(b.getCodigo(),b);
			}
		}
		else {
			dataFiltro.put(b.getStatusBoleto().getCodigo(),new HashMap<String, Map<String,Boleto>>());
			dataFiltro.get(b.getStatusBoleto().getCodigo()).put(
					UtilData.format(b.getDataVencimento(),"yyyyMM"),new HashMap<String,Boleto>());
			dataFiltro.get(b.getStatusBoleto().getCodigo()).get(
					UtilData.format(b.getDataVencimento(),"yyyyMM")).put(b.getCodigo(),b);
		}
	}

	public void atualizaData(Set<Boleto> sb){
		for(Boleto b : sb) atualizaData(b);
	}

	public Set<Boleto> getByAluno(String codAluno){
		getData();
		return dataAluno.get(codAluno);
	}

	public Set<Boleto> getByAluno(String codAluno, String status){
		getData();
		Set<Boleto> r = new HashSet<Boleto>();

		if(dataAluno.containsKey(codAluno))
			for(Boleto b : dataAluno.get(codAluno))
				if(b.getStatusBoleto().getCodigo().equalsIgnoreCase(status))
					r.add(b);
		return r;
	}

	public Set<Boleto> getBoletos(){
		Set<Boleto> r = new HashSet<Boleto>();
		for (String k : getData().keySet())
			r.add(getData().get(k));

		return r;
	}

	public Set<Boleto> getBoletos(Date data_ini, String status){
		Set<Boleto> r = new HashSet<Boleto>();
		String      d = UtilData.format(data_ini,"yyyyMM");

		getData();

		if(status.trim().equals("")){
			for(String s : dataFiltro.keySet())
				if(dataFiltro.get(s).containsKey(d))
					for(String k : dataFiltro.get(s).get(d).keySet())
						r.add(dataFiltro.get(s).get(d).get(k));
		}
		else {
			if(dataFiltro.containsKey(status) && dataFiltro.get(status).containsKey(d))
				for(String k : dataFiltro.get(status).get(d).keySet())
					r.add(dataFiltro.get(status).get(d).get(k));
		}
		return r;
	}

	public String registrarPagamento(String codBoleto,
									Date dataPag,
									String tipoPag,
									int canalPag,
									double valor,
									double desconto,
									double multa)
	{
		Boleto b = get(codBoleto);
		String r = "";

		if(b != null){
			b.setDataPagamento(dataPag);
			b.setPagamentoTipo(tipoPag);
			b.setPagamentoValor(valor);
			b.setPagamentoDesconto(desconto);
			b.setPagamentoMulta(multa);
			b.setPagamentoCanalBoleto(canalPag);
			b.setStatusBoleto("P");

			try {
				BoletoDAO.save(b);
				atualizaData(b);
			}
			catch(Exception e){
				return "Erro ao gravar";
			}
		}
		else
			return "Boleto nao encontrado : " + codBoleto;

		return "OK" + r;
	}

	public String alterarStatus(String codBoleto, String status){
		Boleto b = get(codBoleto);
		String r = "";

		if(b != null){
			b.setStatusBoleto(status);

			try {
				BoletoDAO.save(b);
				atualizaData(b);
			}
			catch(Exception e){
				return "Erro ao gravar";
			}
		}
		else
			return "Boleto nao encontrado : " + codBoleto;

		return "OK" + r;
	}
}